#ifndef CAMSHIFTTRACKER_HPP
#define CAMSHIFTTRACKER_HPP

//------------------------------------------------------------------------------
// Includes 
//------------------------------------------------------------------------------
#include <OpenCV/cv.h>
#include <Tracker/SimpleManeuveringFilter.h>

namespace Tracker
{
	/**
	 * CAMShiftTracker is a class encapsulating the CAMShift functionality of OpenCV.
	 * It provides a set of easy to use functions for parameter setup, 
	 * and runs the CAMShift tracker algorithm in an appropriate manner for most
	 * applications. It also uses a SimpleManeuveringFilter to smooth out 
	 * noise from its measured values. 
	 * <p>
	 * To use this object, set the filters if desired, then call run() for every
	 * image you have. Then when you get to an image displaying a colored object you 
	 * want to track, call learn() with a rectangle corresponding to the position
	 * and size of this object. The tracker will start tracking that color,
	 * and you can call getTrackBox() after every run() to find out where
	 * the object is now.
	 *
	 * @author      Samuel Audet
	 * @version     1.0, 2006-01-21
	 * @since       1.0
	 */
	class CAMShiftTracker {
	public:
	    CAMShiftTracker();
	    virtual ~CAMShiftTracker();    
	
	    /** 
	     * Sets the minimum V value (in the HSV color space) of a pixel 
	     * for it to be processed by CAMShift
	     *
	     * @param vmin      the minimum V value
	     */
	    void setVmin(int vmin = 10) { this->vmin = vmin; }
	    /** 
	     * Sets the maximum V value (in the HSV color space) of a pixel 
	     * for it to be processed by CAMShift
	     *
	     * @param vmax      the maximum V value
	     */
	    void setVmax(int vmax = 256) { this->vmax = vmax; }
	    /** 
	     * Sets the minimum S value (in the HSV color space) of a pixel 
	     * for it to be processed by CAMShift
	     *
	     * @param smin      the minimum S value
	     */
	    void setSmin(int smin = 30) { this->smin = smin; }
	    /** 
	     * Gets the minimum V value (in the HSV color space) of a pixel 
	     * for it to be processed by CAMShift
	     *
	     * @return          the minimum V value
	     */
	    int getVmin() const { return vmin; }
	    /** 
	     * Gets the maximum V value (in the HSV color space) of a pixel 
	     * for it to be processed by CAMShift
	     *
	     * @return          the maximum V value
	     */
	    int getVmax() const { return vmax; }
	    /** 
	     * Gets the minimum S value (in the HSV color space) of a pixel 
	     * for it to be processed by CAMShift
	     *
	     * @return          the minimum S value
	     */
	    int getSmin() const { return smin; }
	
	
	    /** 
	     * Gets the SimpleManeuveringFilter object used to filter the x,y position.
	     *
	     * @return          SimpleManeuveringFilter of the x,y position
	     */
	    SimpleManeuveringFilter &getPositionFilter() { return positionFilter; }
	    /** 
	     * Gets the SimpleManeuveringFilter object used to filter the size (width, height).
	     *
	     * @return          SimpleManeuveringFilter of the size (width, height)
	     */
	    SimpleManeuveringFilter &getSizeFilter() { return sizeFilter; }
	    /** 
	     * Gets the SimpleManeuveringFilter object used to filter the angle.
	     *
	     * @return          SimpleManeuveringFilter of the angle
	     */
	    SimpleManeuveringFilter &getAngleFilter() { return angleFilter; }
	    /** 
	     * Resets all three SimpleManeuveringFilter objects to their default parameters.
	     */
	    void resetFilters();
	
	
	    /** 
	     * Sets the minimum area required for tracking. The area is compared to
	     * what CAMShift returns in comp->rect divided by 255 (see OpenCV documention).
	     * So, the minimum area is basically a value indicated the minimum area in pixel^2
	     * if the "probability" in the "backproject" of all pixels in that area were of 255.
	     * If this minimum is not reached, the tracker will try to latch on to something 
	     * (else) in the image.
	     *
	     * @param a         the minimum area required for tracking
	     */
	    void setMinArea(int a = 300) { minArea = a; }
	    /** 
	     * Gets the currently set minimum area required for tracking. 
	     *
	     * @return          current minimum area required for tracking
	     */
	    int getMinArea() { return minArea; }
	
	
	    /** 
	     * Runs the tracker and processes the image (frame).
	     *
	     * @param frame     image to process 
	     */
	    void run(IplImage* frame);
	
	
	    /** 
	     * Returns the last image received through the run() function. 
	     *
	     * @return          last image received, usually from camera
	     */
	    IplImage* getImage() const { return image; }
	    /** 
	     * Returns an image of the "BackProject". This grayscale image indicates 
	     * the probability that a pixel is of the color stored in the histogram,
	     * 0 = 0.0 and 255 = 1.0. See the documentation of OpenCV for more details.
	     *
	     * @return          the "BackProject" image
	     */
	    IplImage* getBackProject() const { 
	        cvCvtColor(backproject, colorBackproject, CV_GRAY2RGB);
	        return colorBackproject;
	    }
	    /** 
	     * Returns an image of the color histogram, representing the model. 
	     * The tracker will attempt to track the color represented by this histogram. 
	     * See the documentation of OpenCV for more details.
	     *
	     * @return          the color histogram image
	     */
	    IplImage* getHistogramImage() const { return histimg; } 
	    /** 
	     * Returns the actual histogram, representing the model. 
	     * The tracker will attempt to track the color represented by this histogram. 
	     * See the documentation of OpenCV for more details.
	     *
	     * @return          the actual histogram object
	     */
	    CvHistogram* getHistogram() const { return hist; } 
	    /** 
	     * Draws on the image an ellipse representing the currently tracked object.
	     *
	     * @param image     the image to draw an ellipse on
	     */
	    void drawEllipse(IplImage *image) const;
	    /** 
	     * Returns the actual tracking information of the currently tracked object. 
	     * That is, the position, the size, and the angle.
	     *
	     * @return          the tracking information
	     */
	    CvBox2D getTrackBox() const { return track_box; }
	    /** 
	     * Returns the color representing the whole histogram. 
	     * This can be used to color representative objects in a GUI.
	     *
	     * @return          representative tracking color 
	     *                  val[0] = Red, val[1] = Green, val[2] = Blue
	     */
	    CvScalar getTrackColor() const { return tracking_color; }
	
	    /** 
	     * Trains the tracker by building a color histogram from the given 
	     * selection in the image. The selection rectangle refers to the 
	     * image as returned by getImage(). The color histogram will be updated 
	     * after a call to this function and the run() function.
	     *
	     * @param selection  a rectangle indicating where in the image is the color we want to train on
	     */
	    void learn(CvRect selection) { this->selection = selection; track_object = -1; }
	    /** 
	     * Makes the tracker ignore its histogram and return to an untrained state.
	     * Takes effect at the next run() call.
	     */
	    void forget() { track_object = 0; cvZero(histimg); }
	    /** 
	     * Enables tracking as if the object is in selection, but does not train from selection. 
	     * This is useful if we load the histogram from somewhere else. 
	     *
	     * @param selection  a rectangle indicating where the object is now
	     */
	    void enableTracking(CvRect selection);
	
	private:
	    IplImage *image, *hsv, *hue, *mask, *backproject, *histimg, *colorBackproject;
	    CvHistogram *hist;
	
	    int track_object;
	    CvRect selection;
	    CvRect track_window;
	    CvBox2D track_box;
	    CvConnectedComp track_comp;
	    int hdims;
	    int vmin, vmax, smin;
	
	    CvScalar tracking_color;
	
	    CvScalar hsv2rgb(float hue);
	    void buildHistogram(CvRect selection);
	
	    SimpleManeuveringFilter positionFilter, sizeFilter, angleFilter;
	    
	    int minArea;
	};

}

#endif // CAMSHIFTTRACKER_HPP
